home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Utilities / BackSpace / Source / Password.m < prev    next >
Text File  |  1993-07-14  |  7KB  |  310 lines

  1. //  Password.m
  2. //
  3. // implements a simple password protocol for a small amount of security
  4. // as a screen locker.  Can be passed in a view to animate while
  5. // waiting for events to verify a password.  This class isn't as stand-alone
  6. // as it might be, because it sucks its UI stuff out of a nib and relies
  7. // on the nib for a couple of connections, but that could be fixed.
  8. //
  9. //  You may freely copy, distribute, and reuse the code in this example.
  10. //  NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  11. //  fitness for any particular use.
  12.  
  13.  
  14. #import "Password.h"
  15. #import "SpaceView.h"
  16. #import "psfuncts.h"
  17.  
  18.  
  19. #import <appkit/appkit.h>
  20. #import <pwd.h>
  21. #import <objc/NXBundle.h>
  22.  
  23.  
  24. @interface TileView:View
  25. @end
  26. @implementation TileView
  27. - drawSelf:(const NXRect *)rects :(int)rectCount
  28. {
  29.     if (!rects || !rectCount) return self;
  30.     NXDrawButton(&bounds, &bounds);
  31.     return self;
  32. }
  33. @end
  34.  
  35. @implementation Password
  36.  
  37. static const char mess[] = "                   ";    
  38. static const char unMess[] = "";    
  39. static const char salt[] = "Uh";    
  40.  
  41. - init
  42. {
  43.     const char *ptr;
  44.  
  45.     lockEnabled = NO;
  46.  
  47.     ptr = NXGetDefaultValue([NXApp appName], "encryptedPassword");
  48.     if (ptr) safe_strcpy(password, ptr);
  49.     
  50.     return self;
  51. }
  52.  
  53. - setPassword:sender
  54. {
  55.     id ret;
  56.     
  57.     if (![self checkPassword : NXLocalString("Setting password.  Enter old password:",0,0)
  58.             randomPos:NO checkLock:NO withView:nil])
  59.         return nil;
  60.  
  61.  
  62.     [self attemptToSetPassword:
  63.         NXLocalString("Enter new password:\n(NOT your account password!)",0,0)];
  64.     safe_strcpy(attempt2, attempt1);
  65.     [self attemptToSetPassword: NXLocalString("Reenter new password:",0,0)];
  66.  
  67.     if (!strcmp(attempt1, attempt2)) 
  68.     {
  69.         safe_strcpy(password, attempt1);
  70.         NXWriteDefault([NXApp appName], "encryptedPassword", password);
  71.         ret = self;
  72.     }
  73.     else
  74.     {
  75.         [[infoText cell] setStringValue:
  76.             NXLocalString("Error: Passwords didn't match.",0,0)];
  77.         ret = nil;
  78.         [self activePauseWithView:nil];
  79.     }
  80.  
  81.     [window orderOut:self];
  82.     return ret;
  83. }
  84.  
  85. - attemptToSetPassword:(const char *)text
  86. {
  87.     if (!window) [self createWindow];
  88.     
  89.     [[infoText cell] setStringValue:text];
  90.     [self orderWindowToFront];
  91.  
  92.     [NXApp runModalFor:window];
  93.  
  94.     //hey!  I didn't want runmodal to put my window away!
  95.     [self orderWindowToFront];
  96.  
  97.     safe_strcpy(attempt1, 
  98.         (const char *)(crypt((char *)[[clearText cell] stringValue],
  99.         (char *)salt)));
  100.     [[clearText cell] setStringValue: mess];
  101.     [[clearText cell] setStringValue: unMess];
  102.  
  103.     return self;
  104. }
  105.  
  106. - userTypedReturn:sender
  107. {
  108.     [NXApp stopModal];
  109.     return self;
  110. }
  111.  
  112. - (BOOL) checkPassword:(const char *)text randomPos:(BOOL)random 
  113.     checkLock:(BOOL)check withView:aView
  114. {
  115.     BOOL ret;
  116.     NXModalSession session;
  117.     BStimeval timeout = currentTimeInMs() + 6000;
  118.     
  119.     // we check lock to pass if the screen is locked
  120.     // otherwise we always want to verify password
  121.     if ((!lockEnabled && check) || !password[0]) return YES;
  122.     
  123.     // here I allow passage if password has been typed in last 6 seconds
  124.     // NOT! I seem to have had some problems with time wrapping, I nixed this for security
  125.     // if (currentTimeInMs() < (lastPasswordTime + 6000)) return YES;
  126.     
  127.     if (!window) [self createWindow];
  128.  
  129.     [NXApp beginModalSession:&session for:window];
  130.  
  131.     [[infoText cell] setStringValue:text];
  132.     
  133.     if (random) [self randomWindowPosition];
  134.     else [window center];
  135.     [self orderWindowToFront];
  136.  
  137.     for (;;) {
  138.         if ([NXApp runModalSession:&session] != NX_RUNCONTINUES)
  139.             break;
  140.             
  141.         if (currentTimeInMs() > timeout) break;
  142.  
  143.         if (aView)
  144.         {
  145.             [aView lockFocus];
  146.             if ([aView respondsTo:@selector(didLockFocus)]) 
  147.                 [aView didLockFocus];
  148.             [aView oneStep];
  149.             [[aView window] flushWindow];
  150.             NXPing ();    // Synchronize postscript for smoother animation
  151.             [aView unlockFocus];
  152.         }
  153.     }
  154.  
  155.     ret = (!strcmp(password, 
  156.         (crypt((char *)[[clearText cell] stringValue], (char *)salt))));
  157.  
  158.     // on BackSpace password failure, try user password
  159.     if (!ret)
  160.     {
  161.         struct passwd *pwen = getpwuid( getuid() );
  162.         ret = (!strcmp(pwen->pw_passwd,
  163.             (crypt((char *)[[clearText cell] stringValue], pwen->pw_passwd))));
  164.     }
  165.  
  166.     // on user password failure, try root password (only if there is one)
  167.     if (!ret)
  168.     {
  169.         struct passwd *pwen = getpwuid(0);
  170.         if (strlen(pwen->pw_passwd) == 0) ret = 0;
  171.         else ret = (!strcmp(pwen->pw_passwd,
  172.             (crypt((char *)[[clearText cell] stringValue], pwen->pw_passwd))));
  173.     }
  174.  
  175.     [[clearText cell] setStringValue: mess];
  176.     [[clearText cell] setStringValue: unMess];
  177.  
  178.  
  179.  
  180.     // did we get a valid password?
  181.     if (!ret)
  182.     {
  183.         [[infoText cell] setStringValue:
  184.             NXLocalString("Error: Incorrect password.",0,0)];
  185.         [self activePauseWithView:aView];
  186.     }
  187.     else
  188.     {
  189.         lastPasswordTime = currentTimeInMs();
  190.     }
  191.     
  192.     [window orderOut:self];
  193.     [window center];
  194.     
  195.     [NXApp endModalSession:&session];
  196.  
  197.     // this display shouldn't be necessary, but is to ensure timely
  198.     // redraw of a nonretained window.  It looks yucky, though.
  199.     // really should just display area uncovered by panel
  200.     [aView display];
  201.     return ret;
  202. }
  203.  
  204. - orderWindowToFront
  205. {
  206.     [clearText selectText:self];
  207.     [window display];
  208.  
  209.     // make password window float over everything
  210.     PSsetwindowlevel((SAVERTIER+1), [window windowNum]);
  211.  
  212.     [window makeKeyAndOrderFront:self];
  213.     return self;
  214. }
  215.  
  216. - randomWindowPosition
  217. {
  218.     NXRect r;
  219.     NXSize s;
  220.     NXPoint p;
  221.     [NXApp getScreenSize:&s];
  222.     [window getFrame:&r];
  223.     p.x = floor(randBetween(0, s.width - r.size.width));
  224.     p.y = floor(randBetween(0, s.height - r.size.height));
  225.     
  226.     [window moveTo: p.x :p.y];
  227.  
  228.     return self;
  229. }
  230.  
  231.  
  232. - createWindow
  233. {
  234.     NXRect r;
  235.     id tileView;
  236.     
  237.     [contentBox getFrame:&r];
  238.     r.origin.x = r.origin.y = 8;
  239.     [contentBox setFrame:&r];
  240.     r.size.width += 16;
  241.     r.size.height += 16;
  242.     
  243.     window = [[Window alloc]
  244.             initContent:&r style:NX_PLAINSTYLE
  245.             backing:NX_BUFFERED buttonMask:0 defer:NO];
  246.  
  247.     [window center];
  248.     tileView = [[TileView alloc] init];
  249.     
  250.     [contentBox removeFromSuperview];        //not really necessary
  251.     [[window setContentView:tileView] free];
  252.     [tileView addSubview:contentBox];
  253.  
  254.     [window useOptimizedDrawing:YES];
  255.     [window display];
  256.     
  257.     return self;
  258. }
  259.  
  260. - activePauseWithView:aView
  261. {
  262.     BStimeval done;
  263.     
  264.     [window display];
  265.     NXPing();
  266.     done = currentTimeInMs() + 1500;
  267.     if (aView)
  268.     {
  269.         [aView lockFocus];
  270.         if ([aView respondsTo:@selector(didLockFocus)]) [aView didLockFocus];
  271.  
  272.         do {
  273.             [aView oneStep];
  274.             [[aView window] flushWindow];
  275.             NXPing ();    // Synchronize postscript for smoother animation
  276.            } while (currentTimeInMs() < done);
  277.            
  278.         [aView unlockFocus];
  279.     }
  280.     else usleep(1500000);
  281.     return self;
  282. }
  283.  
  284. - setLock:(BOOL)flag;
  285. {
  286.     lockEnabled = flag;
  287.     return self;
  288. }
  289.  
  290. - (BOOL) isLocked
  291. {
  292.     return lockEnabled;
  293. }
  294.  
  295. - (BOOL) validPassword
  296. {
  297.     if (password[0]) return YES;
  298.     return NO;
  299. }
  300.  
  301. // this function just protects me from overrunning to, which 
  302. // is assumed to always be of length LEN
  303. void safe_strcpy(char *to, const char *from)
  304. {
  305.     if (strlen((char *)from) < LEN) strcpy(to,(char *)from);
  306.     else strncpy(to,(char *)from,(LEN-1));
  307. }
  308.  
  309. @end
  310.